<?

/**
 * ACL class
 *
 * Esta clase maneja los acl por usuario
 * @author Alejandro Garcia del Rio <alejandro.garciadelrio@elserver.com>
 * @version 1.0
 * @package ACL
*/
class ACL extends Core {

	static protected $instancia;
	static protected $opciones = array();
	private $id_usuario = null;
	public $error_msg = null;
	private $acl = false; // Permiso momentaneo para modificar acl

	/**
	 * Constructor de la clase.
	 * 
	 * @param integer $id_caso (opcional) El id de caso al que pertenecen estos tags
	 * @param array $opciones (opcional) Opciones validas para esta clase
	 */
	function __construct ($id_usuario=null, $opciones=null) {
		// Llamo al constructor del parent tambien
		parent::__construct();
		// Guardo las opciones si me definio alguna
		if ($opciones)
			$this->opciones($opciones);
		// Seteo el id de caso
		$this->usuario($id_usuario);
	}

	/**
	 * Setea las opciones 
	 * 
	 * @param array $opciones (opcional) Opciones validas para esta clase. Si esta vacio, funciona como un getter.
	 * @return array $opciones Listado de opciones
	 */
	public function opciones ($opciones=null) {
		return self::$opciones = parent::opciones(self::$opciones, $opciones);
	}

	/**
	 * Devuelve una unica instancia de esta clase
	 * 
	 * @return object Instancia de esta clase
	 */
	public static function getInstance() {
		if (!self::$instancia instanceof self)
			self::$instancia = new self;
		return self::$instancia;
	}

	/**
	 * Setea el id de usuario al que corresponde este acl
	 * 
	 * @param integer $id_usuario (opcional) El id del usuario.
	 * @return integer El id del usuario
	 */
	public function usuario ($id_usuario=null) {

		// Obtengo un objeto de sesion
		$Session = Session::getInstance();

		// Si no hay un usuario definido, lo tomo de la sesion
		if (!$id_usuario && !$this->id_usuario)
			$id_usuario = $Session->get('usuario.id');

		if ($id_usuario)
			$this->id_usuario = addslashes($id_usuario);

		return $this->id_usuario;
	}

	/**
	 * Devuelve el listado de acciones posibles
	 * 
	 * @return array $acciones
	 */
	public function acciones () {

		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();

		// Obtengo las acciones de la base y genero el listado
		$acciones = array();
		if ($_acciones = $db->get_results("SELECT * FROM acl_acciones ORDER BY id_accion"))
			foreach ($_acciones as $_accion)
				$acciones[$_accion['id_accion']] = $_accion['accion'];

		return $acciones;
	}
	
	/**
	 * Devuelve el listado de permisos posibles
	 * 
	 * @return array $permisos
	 */
	public function permisos () {

		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();

		// Obtengo las acciones de la base y genero el listado
		$permisos = array();
		if ($_permisos = $db->get_results("SELECT * FROM acl ORDER BY id_acl"))
			foreach ($_permisos as $_permiso)
				$permisos[$_permiso['id_acl']] = $_permiso['acl'];

		return $permisos;
	}

	/**
	 * Devuelve el id de una accion, recibiendo su nombre
	 * 
	 * @param string $accion
	 * @return int
	 */
	public function id_accion ($accion) {

		// Saneamiento de variables
		$accion = addslashes($accion);

		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();

		return $db->get_var("SELECT aa.id_accion FROM acl_acciones aa WHERE aa.accion = '".$accion."'");
	}

	/**
	 * Devuelve el id de un acl, recibiendo su nombre
	 * 
	 * @param string $acl
	 * @return int
	 */
	public function id ($acl) {

		// Saneamiento de variables
		$acl = addslashes($acl);

		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();

		return $db->get_var("SELECT a.id_acl FROM acl a WHERE a.acl = '".$acl."'");
	}

	/**
	 * Setea un acl para un usuario
	 * 
	 * @param string $acl Acl a agregar
	 * @param string $accion La accion a agregar sobre ese acl
	 * @param int $id_usuario (Opcional) Id del usuario al que se le quiere agregar el acl. Si esta vacio, toma el usuario logueado
	 * @return boolean
	 */
	public function set ($acl, $accion=null, $id_usuario=null) {

		// Obtengo el id del acl
		$id_acl = ($this instanceof self)? $this->id($acl) : self::id($acl);

		// No existe el acl
		if (!$id_acl)
			return ($this)? $this->fail('No se encontro el acl solicitado') : false;

		// Obtengo las acciones posibles
		$acciones = ($this instanceof self)? $this->acciones : self::acciones();

		// Obtengo el id de la accion
		$id_accion = ($this instanceof self)? $this->id_accion($accion) : self::id_accion($accion);

		// No existe la accion
		if (!$id_accion)
			return ($this)? $this->fail('No se encontro la accion solicitada') : false;

		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();

		// Seteo el id de usuario
		if (($id_usuario) && $this instanceof self)
			$this->usuario($id_usuario);

		// Si esta instanciada la clase, uso $this
		$id_usuario = ($this instanceof self)? $this->usuario() : addslashes($id_usuario);

		// Valido que tenga un id de usuario
		if (!$id_usuario)
			return ($this)? $this->fail('No hay un id de usuario especificado') : false;

		// Obtengo el objeto de sesion
		$Session = ($this)? $this->Session : Session::getInstance();
			
		// Me fijo que el usuario logueado tenga permisos para setear un acl
		if (!self::get('ACL', 'AGREGAR', $Session->get('usuario.id')) && !$this->acl)
			return ($this)? $this->fail('No tiene permisos para ejecutar la accion ACL::AGREGAR') : false;

		// Agrego el acl a la base
		$db->insert('acl_usuarios', array('id_acl' => $id_acl, 'id_accion' => $id_accion, 'id_usuario' => $id_usuario));
		
		//$db->debug();

		return true;
	}

	/**
	 * Quita un acl para un usuario
	 * 
	 * @param string $acl Acl a quitar
	 * @param string $accion La accion a quitar sobre ese acl
	 * @param int $id_usuario (Opcional) Id del usuario al que se le quiere quitar el acl. Si esta vacio, toma el usuario logueado
	 * @return boolean
	 */
	public function del ($acl, $accion, $id_usuario=null) {

		// Obtengo el id del acl
		$id_acl = ($this instanceof self)? $this->id($acl) : self::id($acl);

		// No existe el acl
		if (!$id_acl)
			return ($this)? $this->fail('No se encontro el acl solicitado') : false;

		// Obtengo las acciones posibles
		$acciones = ($this instanceof self)? $this->acciones : self::acciones();

		// Obtengo el id de la accion
		$id_accion = ($this instanceof self)? $this->id_accion($accion) : self::id_accion($accion);

		// No existe la accion
		if (!$id_accion)
			return ($this)? $this->fail('No se encontro la accion solicitada') : false;

		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();

		// Seteo el id de usuario
		if (($id_usuario) && $this instanceof self)
			$this->usuario($id_usuario);

		// Si esta instanciada la clase, uso $this
		$id_usuario = ($this instanceof self)? $this->usuario() : addslashes($id_usuario);

		// Valido que tenga un id de usuario
		if (!$id_usuario)
			return ($this)? $this->fail('No hay un id de usuario especificado') : false;
		
		// Obtengo el objeto de sesion
		$Session = ($this)? $this->Session : Session::getInstance();

		// Me fijo que tenga permisos para eliminar un acl
		if (!self::get('ACL', 'ELIMINAR', $Session->get('usuario.id')))
			return ($this)? $this->fail('No tiene permisos para ejecutar la accion ACL::ELIMINAR') : false;

		// Quito el acl en la base
		$db->query("DELETE FROM acl_usuarios WHERE id_acl = '$id_acl' AND id_accion = '$id_accion' AND id_usuario = '$id_usuario' LIMIT 1");

		return true;
	}

	/**
	 * Devuelve si un usuario tiene determinado acl/accion o no
	 * 
	 * @param string $acl Acl que se quiere averiguar si tiene acceso
	 * @param string $accion La accion sobre la que se quiere averiguar si tiene acceso
	 * @param int $id_usuario (Opcional) Id del usuario en cuestion. Si esta vacio, toma el usuario logueado
	 * @return boolean
	 */
	public function get ($acl, $accion, $id_usuario=null) {

		// Saneamiento de variables
		$acl = addslashes($acl); $accion = addslashes($accion);

		// Obtengo el id del acl
		$id_acl = ($this instanceof self)? $this->id($acl) : self::id($acl);

		// No existe el acl
		if (!$id_acl)
			return ($this)? $this->fail('No se encontro el acl solicitado') : false;

		// Obtengo las acciones posibles
		$acciones = ($this instanceof self)? $this->acciones() : self::acciones();

		// Obtengo el id de la accion
		$id_accion = ($this instanceof self)? $this->id_accion($accion) : self::id_accion($accion);

		// No existe la accion
		if (!$id_accion)
			return ($this)? $this->fail('No se encontro la accion solicitada') : false;

		// Seteo el id de usuario
		if (($id_usuario) && $this instanceof self)
			$this->usuario($id_usuario);

		// Si esta instanciada la clase, uso $this
		$id_usuario = ($this instanceof self)? $this->usuario() : addslashes($id_usuario);

		// Valido que tenga un id de usuario
		if (!$id_usuario)
			return ($this)? $this->fail('No hay un id de usuario especificado') : false;

		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();

		// Averiguo si existe el acl/accion para este usuario
		$res = (boolean)$db->get_var("SELECT id_acl FROM acl_usuarios WHERE id_acl = $id_acl AND id_usuario = $id_usuario AND id_accion = $id_accion");

		// Si dio falso, busco si este acl/accion tiene mensaje de error definido
		if (!$res && ($error = $db->get_var("SELECT error FROM acl_acl_acciones WHERE id_acl = $id_acl AND id_accion = $id_accion")) && !empty($error))
			$this->error_msg = $error;

		return $res;
	}

	/**
	 * Devuelve el listado con todos los acl
	 * 
	 * @return array
	 */
	public function all () {
		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();

		return $db->get_results("SELECT * FROM acl WHERE activo = 1");
	}

	/**
	 * Devuelve todos los permisos de este usuario
	 * 
	 * @param int $id_usuario (Opcional) Id del usuario en cuestion. Si esta vacio, toma el usuario logueado
	 * @return array
	 */
	public function usuario_permisos ($id_usuario=null) {

		// Seteo el id de usuario
		if (($id_usuario) && $this instanceof self)
			$this->usuario($id_usuario);

		// Si esta instanciada la clase, uso $this
		$id_usuario = ($this instanceof self)? $this->usuario() : addslashes($id_usuario);

		// Valido que tenga un id de usuario
		if (!$id_usuario)
			return ($this)? $this->fail('No hay un id de usuario especificado') : false;

		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();

		// Busco todos los permisos de este usuario
		$permisos = array();
		if ($_permisos = $db->get_results("SELECT a.acl, aa.accion FROM acl a, acl_acciones aa, acl_usuarios au
						WHERE a.id_acl = au.id_acl AND aa.id_accion = au.id_accion AND au.id_usuario = '$id_usuario' 
						ORDER BY au.id_acl, au.id_accion"))
			foreach ($_permisos as $_permiso) 
				$permisos[$_permiso['acl']][$_permiso['accion']] = 1;
				
		return $permisos;
	}

	/**
	 * Remueve todos los permisos de un usuario
	 * 
	 * @param int $id_usuario (Opcional) Id del usuario en cuestion. Si esta vacio, toma el usuario logueado
	 * @return boolean
	 */
	public function clear ($id_usuario=null) {

		// Seteo el id de usuario
		if (($id_usuario) && $this instanceof self)
			$this->usuario($id_usuario);

		// Si esta instanciada la clase, uso $this
		$id_usuario = ($this instanceof self)? $this->usuario() : addslashes($id_usuario);

		// Valido que tenga un id de usuario
		if (!$id_usuario)
			return ($this)? $this->fail('No hay un id de usuario especificado') : false;
		
		// Obtengo el objeto de sesion
		$Session = ($this)? $this->Session : Session::getInstance();
	
		// Me fijo que el usuario logueado tenga permisos para eliminar un acl
		if (!self::get('ACL', 'ELIMINAR', $Session->get('usuario.id')))
			return ($this)? $this->fail('No tiene permisos para ejecutar la accion ACL::ELIMINAR') : false;

		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();
		
		// Borro todos los acl de este usuario
		$db->query("DELETE FROM acl_usuarios WHERE id_usuario = '$id_usuario' AND id_acl != 9");

		// Averiguo si existe el acl/accion para este usuario
		return true;

	}

	/**
	 * Reemplaza los acl de un usuario por los recibidos. Elimina los que tenia antes
	 * 
	 * @param array $acls Array de ACL a setear. Formato array('ACL1' => array('ACCION1' => 1, 'ACCION2' => 1), ...)
	 * @param int $id_usuario (Opcional) Id del usuario en cuestion. Si esta vacio, toma el usuario logueado
	 * @return boolean
	 */
	public function replace ($acls, $id_usuario=null) {
	
		// Seteo el id de usuario
		if (($id_usuario) && $this instanceof self)
			$this->usuario($id_usuario);

		// Si esta instanciada la clase, uso $this
		$id_usuario = ($this instanceof self)? $this->usuario() : addslashes($id_usuario);

		// Valido que tenga un id de usuario
		if (!$id_usuario)
			return ($this)? $this->fail('No hay un id de usuario especificado') : false;
			
		// Obtengo el objeto de sesion
		$Session = ($this)? $this->Session : Session::getInstance();

		// Me fijo que el usuario logueado tenga permisos para setear un acl
		if (!self::get('ACL', 'AGREGAR', $Session->get('usuario.id')))
			return ($this)? $this->fail('No tiene permisos para ejecutar la accion ACL::AGREGAR') : false;

		$this->acl = true;

		// Vacio todos los ACL
		if (!self::clear($id_usuario))
			return false;

		if (is_array($acls) && !empty($acls))
			foreach ($acls as $acl => $acciones)
				if (is_array($acciones) && !empty($acciones))
					foreach ($acciones as $accion => $val)
						self::set($acl, $accion, $id_usuario);

		$this->acl = false;

		return true;
	}

	/**
	 * Devuelve el listado de acl y acciones en formato basico para la interfaz basica
	 * 
	 * @return array
	 */
	public function acl_acciones () {

		// Obtengo un objeto de conexion a la base
		$db = ($this)? $this->db : ez_sql::getInstance();

		// Obtengo los acl de la tabla de la interfaz basica
		$acls = $db->get_results("SELECT aaa.*, ag.grupo FROM acl_acl_acciones aaa, acl_grupos ag
								WHERE aaa.id_grupo = ag.id_grupo ORDER BY ag.orden");
				
		// Los agrupo por grupo	
		$grupo = array();
		if ($acls)
			foreach ($acls as $acl) {
				$grupo[$acl['id_grupo']]['grupo'] = $acl['grupo'];
				$grupo[$acl['id_grupo']]['acls'][] = array(
					'id_acl' => $acl['id_acl'],
					'id_accion' => $acl['id_accion'],
					'nombre' => $acl['nombre'],
					'descripcion' => $acl['descripcion']
				);
			}

		return $grupo;

	}

	/*
	* Descripcion: Devuelve el mensaje de error de la llamada a acl::get()
	* Return: String
	*/
	function error_msg() {
		return $this->_error_msg;
	}

}

?>
